﻿using Lanbt.Core.Entity;
using Lanbt.Core.Entity.EntityDB;
using Lanbt.Core.Repository.SqlService.IRepository;
using Lanbt.Core.Utility;
using Lanbt.Core.Utility.Extent;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using SqlSugar;
using System.Linq.Expressions;

namespace Lanbt.Core.Repository.SqlService
{
    public class RepositoryBase<T> : IRepositoryBase<T> where T: EntityBase,new()
    {
        public ISqlSugarClient _db { get; set; }
        private readonly IHttpContextAccessor  _httpContextAccessor;

        public RepositoryBase(ISqlSugarClient db)
        {
            _db = db;
            _httpContextAccessor = GlobalContext.ServiceProvider?.GetService<IHttpContextAccessor>();
        }

        public CurrentUser _currentUser
        {
            get
            {
                try
                {
                    return (CurrentUser)_httpContextAccessor.HttpContext?.User;
                }
                catch
                {
                    return new CurrentUser();
                }
            }
        }

        public async Task<int> Count(bool isAll = false)
        {
            if (!isAll)
            {
                return await _db.Queryable<T>().Where(q => !q.IsDelete).CountAsync();
            }
            return await _db.Queryable<T>().CountAsync();
        }

        public async Task<int> Count(Expression<Func<T, bool>> where, bool isAll = false)
        {
            if (!isAll)
            {
                where = where.And(q => !q.IsDelete);
            }
            return await _db.Queryable<T>().Where(where).CountAsync();
        }

        public async Task<T> FirstOrDefault(bool isAll = false)
        {
            if (!isAll)
            {
                return await _db.Queryable<T>().OrderBy(q => q.CreateTime).FirstAsync(q => !q.IsDelete);
            }
            return await _db.Queryable<T>().OrderBy(q => q.CreateTime).FirstAsync();
        }

        public async Task<T> FirstOrDefault(string id,bool isAll = false)
        {
            if (!isAll)
            {
                return await _db.Queryable<T>().OrderBy(q => q.CreateTime).FirstAsync(q =>q.ID == id && !q.IsDelete);
            }
            return await _db.Queryable<T>().OrderBy(q => q.CreateTime).FirstAsync(q=>q.ID == id);
        }

        public async Task<T> FirstOrDefault(Expression<Func<T, bool>> where,bool isAll = false)
        {
            if (!isAll)
            {
                where = where.And(q => !q.IsDelete);
            }
            return await _db.Queryable<T>().OrderBy(q=>q.CreateTime).FirstAsync(where);
        }

        public async Task<T> FirstOrDefaultOrderByDesc(Expression<Func<T, object>> order)
        {
            return await _db.Queryable<T>().OrderByDescending(order).FirstAsync();
        }

        public async Task<T> FirstOrDefaultOrderByDesc(Expression<Func<T, bool>> where, Expression<Func<T, object>> order, bool isAll = false)
        {
            if (!isAll)
            {
                where = where.And(q => !q.IsDelete);
            }
            return await _db.Queryable<T>().OrderByDescending(order).FirstAsync(where);
        }

        public async Task<IList<T>> GetAll(bool isAll = false)
        {
            if (!isAll)
            {
                return await _db.Queryable<T>().Where(q => !q.IsDelete).OrderBy(q => q.CreateTime).ToListAsync();
            }
            return await _db.Queryable<T>().OrderBy(q => q.CreateTime).ToListAsync();
        }

        public async Task<IList<T>> Query(Expression<Func<T, bool>> where, bool isAll = false)
        {
            if (!isAll)
            {
                where = where.And(q => !q.IsDelete);
            }
            return await _db.Queryable<T>()
                            .Where(where)
                            .OrderBy(q => q.CreateTime)
                            .ToListAsync();
        }

        public async Task<IList<T>> Query(Expression<Func<T, bool>> where, Expression<Func<T, object>> order, bool isAll = false)
        {
            if (!isAll)
            {
                where = where.And(q => !q.IsDelete);
            }
            return await _db.Queryable<T>()
                            .Where(where)
                            .OrderBy(order)
                            .ToListAsync();
        }

        public async Task<IList<T>> QueryOrderByDesc(Expression<Func<T, bool>> where, Expression<Func<T, object>> order, bool isAll = false)
        {
            if (!isAll)
            {
                where = where.And(q => !q.IsDelete);
            }
            return await _db.Queryable<T>()
                            .Where(where)
                            .OrderByDescending(order)
                            .ToListAsync();
        }

        public async Task<Tuple<int, IList<T>>> QueryToPageList(int pageIndex, int pageSize)
        {
            RefAsync<int> total = 0;
            var list = await _db.Queryable<T>()
                            .OrderBy(q=>q.CreateTime)
                            .ToPageListAsync(pageIndex, pageSize, total);
            return new Tuple<int,IList<T>>(total, list);
        }

        public async Task<Tuple<int, IList<T>>> QueryToPageList(int pageIndex, int pageSize, Expression<Func<T, bool>> where, bool isAll = false)
        {
            if (!isAll)
            {
                where = where.And(q => !q.IsDelete);
            }
            RefAsync<int> total = 0;
            var list = await _db.Queryable<T>()
                          .Where(where)
                          .OrderBy(q=>q.CreateTime)
                          .ToPageListAsync(pageIndex, pageSize, total);
            return new Tuple<int, IList<T>>(total, list);
        }

        public async Task<Tuple<int, IList<T>>> QueryToPageListOrderBy(int pageIndex, int pageSize, Expression<Func<T, bool>> where, Expression<Func<T, object>> order, bool isAll = false)
        {
            if (!isAll)
            {
                where = where.And(q => !q.IsDelete);
            }
            RefAsync<int> total = 0;
            var list = await _db.Queryable<T>()
                          .Where(where)
                          .OrderBy(order)
                          .ToPageListAsync(pageIndex, pageSize, total);
            return new Tuple<int, IList<T>>(total, list);
        }

        public async Task<Tuple<int, IList<T>>> QueryToPageListOrderByDesc(int pageIndex, int pageSize, Expression<Func<T, bool>> where, Expression<Func<T, object>> order, bool isAll = false)
        {
            if (!isAll)
            {
                where = where.And(q => !q.IsDelete);
            }
            RefAsync<int> total = 0;
            var list = await _db.Queryable<T>()
                          .Where(where)
                          .OrderByDescending(order)
                          .ToPageListAsync(pageIndex, pageSize, total);
            return new Tuple<int, IList<T>>(total, list);
        }

        public async Task<string> InsertOne(T entity)
        {
            entity.CreatedId = _currentUser.Id;
            entity.CreateTime = DateTime.Now;
            entity.ModificaTime = DateTime.Now;
            entity.ModifiedId = _currentUser.Id;
            await _db.Insertable(entity).ExecuteCommandAsync();
            return entity.ID;
        }

        public async Task<int> InsertMany(IList<T> entitys)
        {
            foreach (var entity in entitys)
            {
                entity.CreatedId = _currentUser.Id;
                entity.CreateTime = DateTime.Now;
                entity.ModificaTime = DateTime.Now;
                entity.ModifiedId = _currentUser.Id;
            }
            return await _db.Insertable<T>(entitys).ExecuteCommandAsync();
        }

        public async Task<int> BulkInsert(IList<T> entitys)
        {
            foreach (var entity in entitys)
            {
                entity.CreatedId = _currentUser.Id;
                entity.CreateTime = DateTime.Now;
                entity.ModificaTime = DateTime.Now;
                entity.ModifiedId = _currentUser.Id;
            }
            return await _db.Fastest<T>().BulkCopyAsync(entitys.ToList());
        }


        public async Task<int> UpdateOne(T entity)
        {
            entity.ModifiedId = _currentUser.Id;
            entity.ModificaTime = DateTime.Now;
            return await _db.Updateable(entity).ExecuteCommandAsync();
        }

        public async Task<int> UpdateMany(IList<T> entitys)
        {
            foreach (var entity in entitys)
            {
                entity.ModifiedId = _currentUser.Id;
                entity.ModificaTime = DateTime.Now;
            }
            return await _db.Updateable<T>(entitys).ExecuteCommandAsync();
        }

        public async Task<int> BulkUpdate(IList<T> entitys)
        {
            foreach (var entity in entitys)
            {
                entity.ModifiedId = _currentUser.Id;
                entity.ModificaTime = DateTime.Now;
            }
            return await _db.Fastest<T>().BulkUpdateAsync(entitys.ToList());
        }

        public async Task Delete_false(string id)
        {
            T entity = await FirstOrDefault(q => q.ID == id);
            entity.IsDelete = true;
            entity.ModifiedId = _currentUser.Id;
            entity.ModificaTime = DateTime.Now;
            await UpdateOne(entity);
        }

        public async Task Delete_false(IList<string> ids)
        {
            IList<T> entitys = await Query(q => ids.Contains(q.ID));
            foreach (var entity in entitys)
            {
                entity.IsDelete = true;
                entity.ModifiedId = _currentUser.Id;
                entity.ModificaTime = DateTime.Now;
            }
            await UpdateMany(entitys);
        }

        public async Task Delete_false(T entity)
        {
            await Delete_false(entity.ID);
        }

        public async Task Delete_false(IList<T> entitys)
        {
            var ids = entitys.Select(x => x.ID).ToList();
            await Delete_false(ids);
        }

        public async Task Delete_false(Expression<Func<T, bool>> where, bool isAll = false)
        {
            if (!isAll)
            {
                where = where.And(q => !q.IsDelete);
            }
            IList<T> entitys = await Query(where);
            foreach (var entity in entitys)
            {
                entity.IsDelete = true;
                entity.ModifiedId = _currentUser.Id;
                entity.ModificaTime = DateTime.Now;
            }
            await UpdateMany(entitys);
        }

        public async Task Delete_true(string id)
        {
            await _db.Deleteable<T>().In(id).ExecuteCommandAsync();
        }

        public async Task Delete_true(IList<string> ids)
        {
            await _db.Deleteable<T>().In(ids.ToArray()).ExecuteCommandAsync();
        }

        public async Task Delete_true(T entity)
        {
            await Delete_true(entity.ID);
        }

        public async Task Delete_true(IList<T> entitys)
        {
            var ids = entitys.Select(x => x.ID).ToList();
            await Delete_true(ids);
        }

        public async Task Delete_true(Expression<Func<T, bool>> where,bool isAll = false)
        {
            if (!isAll)
            {
                where = where.And(q => !q.IsDelete);
            }
            var list = await Query(where);

            await _db.Deleteable<T>(list).ExecuteCommandAsync();
        }

        public Task<bool> DropTable()
        {
            return Task.FromResult(_db.DbMaintenance.TruncateTable<T>());
        }
    }
}
